package com.lcf.ext;

import com.lcf.anno.ExtResource;
import com.lcf.anno.ExtService;
import com.lcf.utils.ClassUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ExtClassPathXmlApplicationContext {

    private String packageName;

    //bean容器,如果value为Class地址时，会创建两次对象
//    public ConcurrentHashMap<String, Class<?>> beans = null;
    public ConcurrentHashMap<String, Object> beans = null;

    public ExtClassPathXmlApplicationContext(String packageName) throws Exception {
        //初始化bean容器
        beans = new ConcurrentHashMap<String, Object>();
        this.packageName = packageName;
        initBeans();
        initAttr();
    }

    //初始化属性
    public void initAttr() throws Exception {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object value = entry.getValue();
            attrAssign(value);
        }
    }

    public Object getBean(String beanId) throws Exception {
        //初始化bean容器
        if (StringUtils.isEmpty(beanId)) {
            throw new Exception("请传入正确的beanId");
        }

        //Class<?> aClass = beans.get(beanId);
        Object o = beans.get(beanId);
//        if (null == aClass) {
//            throw new Exception("class not found");
//        }
        return o;
    }

    /**
     * 1.使用java的反射机制扫包，获取当前包下所有的类
     * 2.判断类上是否存在注入bean的注解
     * 3.使用java的反射机制进行初始化
     */
    public void initBeans() throws Exception {

        List<Class<?>> classes = ClassUtils.getClasses(packageName);
        ConcurrentHashMap<String, Object> beans = findClassExistAnnotation(classes);
        if (beans.size() == 0 || beans == null) {
            throw new Exception("当前包下无此注解");
        }
    }

    //判断类上是否存在注入bean的注解
    public ConcurrentHashMap<String, Object> findClassExistAnnotation(List<Class<?>> classes) throws Exception {
        for (Class<?> clazz : classes) {
            //判断类上是否有注解
            ExtService annotation = clazz.getAnnotation(ExtService.class);
            if (null != annotation) {
                //此时能获取注解，那么名字必定不为空
                String className = clazz.getSimpleName();
                String beanId = toLowerCaseFirstOne(className);
                beans.put(beanId, clazz.newInstance());
            }
        }
        return beans;
    }

    public void attrAssign(Object object) throws Exception {
        //1.使用反射机制，获取当前类的所有属性
        Field[] fields = object.getClass().getDeclaredFields();

        for (Field field : fields) {
            //判断当前属性是否存在该注解
            ExtResource extResource = field.getAnnotation(ExtResource.class);
            if (null != extResource) {
                //获取属性名称
                String fieldName = field.getName();
                Object bean = getBean(fieldName);
                if (null != bean) {
                    //为true时可以获取到私有属性
                    field.setAccessible(true);
                    field.set(object, bean);
                }
            }
        }
    }

    // 首字母转小写
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }
}
